import copy
from typing import Any, List, Tuple
from .connection import Connection
from ..conf import db_type_dict
from ..exception import DBExporterTypeException


def export_db(conn: Connection):
    db_plugin = conn.get_plugin()
    db_conf = db_type_dict[conn.conn_type]["conf"]


class DBStructInfo(object):
    def __init__(self, conn: Connection):
        self.conn = conn
        self.db_plugin = conn.get_plugin()
        self.schema_list = []

        self.db_conf = db_type_dict[conn.conn_type]["conf"]

        if not isinstance(self.db_conf, dict):
            raise DBExporterTypeException("db_conf except dict, but %s" % type(self.db_conf))

        if isinstance(self.db_conf["schema"], dict):
            if "sql" in self.db_conf["schema"]:
                self.schema_list = [record[0] for record in self.db_plugin.get_records(self.db_conf["schema"]["sql"])]

        self.split_col = []
        if "split_cols" in self.db_conf:
            self.split_cols = str(self.db_conf["split_cols"]).lower().split(",")

        self.comm_skip_cols = []
        if "split_col" in self.db_conf:
            self.comm_skip_cols = [col.lower().strip() for col in str(self.db_conf["skip_cols"]).split(",")]

        self.comm_order_cols = []
        if "order_cols" in self.db_conf:
            self.comm_order_cols = [col.lower().strip() for col in str(self.db_conf["order_cols"]).split(",")]

        self.all_tables_dict = {}
        self.all_table_split_record_dict = {}

    def _get_order_cols(self, order_cols_dict, raw_cols) -> list:
        tab_order_cols = [(col, order_cols_dict[col]) for col in raw_cols if col in order_cols_dict]
        if len(tab_order_cols) == 0:
            return []
        else:
            tab_order_cols = sorted(tab_order_cols, key=lambda r: r[1])
            return [key for key, idx in tab_order_cols]

    def _get_need_table_cols(self, skip_cols, table_cols):
        # 部分环境中的同名表列的默认顺序不一致，故需列名排序
        return sorted([col for col in table_cols if col not in skip_cols])

    def _get_split_col(self, raw_cols):
        for col in self.split_cols:
            if col in raw_cols:
                return col
        return None

    def parse_table_conf(self):
        db_conf = self.db_conf
        all_tables_dict = {}
        if len(db_conf["table"]) == 0:
            return all_tables_dict

        for table_conf in db_conf["table"]:
            table_dict = {"table_name": str(table_conf["table_name"]).lower().strip()}
            table_name = table_conf["table_name"]
            table_cols = None
            if "cols" in table_conf:
                table_cols = [col.lower().strip() for col in str(table_conf["cols"]).split(",")]

            table_order_cols = self.comm_order_cols
            if "order_cols" in table_conf:
                table_order_cols = [col.lower().strip() for col in str(table_conf["order_cols"]).split(",")]
            order_cols_dict = {col: i for i, col in enumerate(table_order_cols)}

            table_skip_cols = copy.deepcopy(self.comm_skip_cols)
            if "skip_cols" in table_conf:
                table_skip_cols = table_skip_cols + [col.lower().strip() for col in str(table_conf["skip_cols"]).split(",")]

            if table_cols is None:
                table_dict["cols"] = [str(col).lower() for col in self.db_plugin.get_cols(table_name)]
            else:
                table_dict["cols"] = table_cols

            # 将表列按照需求进行排序
            table_dict["order_cols"] = self._get_order_cols(order_cols_dict, table_dict["cols"])

            # 生成表查询的列
            # 为方便beyond进行比对，需要将关键列提前，从而避免数据差异时难以对齐
            raw_need_table_cols = self._get_need_table_cols(table_skip_cols, table_dict["cols"])
            if table_dict["order_cols"] is None or len(table_dict["order_cols"]) == 0:
                table_dict["need_cols"] = raw_need_table_cols
            else:
                need_cols = copy.deepcopy(table_dict["order_cols"])
                for col in raw_need_table_cols:
                    if col not in table_dict["order_cols"]:
                        need_cols.append(col)
                table_dict["need_cols"] = need_cols

            table_dict["split_col"] = self._get_split_col(table_dict["need_cols"])

            # 生成表对应的SQL文件
            cols_src_str = ",".join(table_dict["need_cols"])
            order_cols_str = "1"
            if not len(table_dict["order_cols"]) == 0:
                order_cols_str = ",".join(table_dict["order_cols"])
            sql_src = "select {cols_str} from {table_name} order by {order_cols} " \
                .format(cols_str=cols_src_str, table_name=table_dict["table_name"], order_cols=order_cols_str)
            table_dict["sql_src"] = sql_src

            all_tables_dict[table_dict["table_name"]] = table_dict

        self.all_tables_dict = all_tables_dict

        return all_tables_dict

    def get_table_split_record_dict(self) -> dict:
        all_table_split_record_dict = {}
        for tab_item in self.all_tables_dict.values():
            all_table_split_record_dict[tab_item["table_name"]] = {}
            split_col = tab_item["split_col"]
            tab_records = self.db_plugin.get_records(tab_item["sql_src"], cursor="dictcursor")

            split_record_dict = all_table_split_record_dict[tab_item["table_name"]]
            split_record_dict["__cols"] = tab_item["need_cols"]
            if split_col is None:
                split_record_dict["_global"] = tab_records
            else:
                for schema in self.schema_list:
                    split_record_dict[schema] = []

                for row_dict in tab_records:
                    if row_dict[split_col] in split_record_dict:
                        split_record_dict[row_dict[split_col]].append(row_dict)
        self.all_table_split_record_dict = all_table_split_record_dict
        return self.all_table_split_record_dict


